﻿using System;

/// <summary>
/// C# Date Differential
/// Object that calculates the days, months, and years... since or until another earlierDate.
/// </summary>
namespace MikeKappel.Com.CS.Model
{

    /// <summary>
    /// DateDifferential is for returning the difference 
    /// between two dates in the year, month, and day format
    /// </summary>
    public class DateDifferential
    {
        /// <summary>
        /// Count Up from date, Countdown from date, or Equal  
        /// </summary>
        public enum DateDifferentialType
        {
            /// <summary>
            ///  Count Up from date
            ///  Time since date
            /// </summary>
            Ascending,
            /// <summary>
            ///  Countdown to date
            ///  Time until date
            /// </summary>
            Descending,
            /// <summary>
            /// Dates are the same
            /// </summary>
            Equal
        }
        public enum DetailType
        {
            /// <summary>
            /// Include days
            /// </summary>
            Days,
            /// <summary>
            /// Include hours
            /// </summary>
            Hours,
            /// <summary>
            /// Include hours
            /// </summary>
            Minutes,
            /// <summary>
            /// Include seconds
            /// </summary>
            Seconds,
            /// <summary>
            /// Include milliseconds
            /// </summary>
            Milliseconds
        }

        /// <summary>
        /// Countdown, Count Up, or Equal
        /// </summary>
        public DateDifferentialType Type
        {
            get
            {
                return type;
            }
        }
        private DateDifferentialType type;

        /// <summary>
        /// The amount of detail that should be shown
        /// Auto, Days, Hours, Minutes, Seconds, or Milliseconds
        /// </summary>
        public DetailType AmountOfDetail
        {
            get
            {
                return amountOfDetail;
            }
        }
        private DetailType amountOfDetail;

        /// <summary>
        /// Millennium part of the difference between dates
        /// </summary>
        public Int32? Millennia
        {
            get
            {
                return millennia;
            }
        }
        public Int32? millennia;

        /// <summary>
        /// Century part of the difference between dates
        /// </summary>
        public Int32? Centuries
        {
            get
            {
                return centuries;
            }
        }
        public Int32? centuries;

        /// <summary>
        /// Decade part of the difference between dates
        /// </summary>
        public Int32? Decades
        {
            get
            {
                return decades;
            }
        }
        public Int32? decades;

        /// <summary>
        /// Year part of the difference between dates
        /// </summary>
        public Int32? Years
        {
            get
            {
                return years;
            }
        }
        public Int32? years;

        /// <summary>
        /// Month part of the difference between dates
        /// </summary>
        public Int32? Months
        {
            get
            {
                return months;
            }
        }
        public Int32? months = 0;

        /// <summary>
        /// Day part of the difference between dates
        /// </summary>
        public Int32? Weeks
        {
            get
            {
                return weeks;
            }
        }
        public Int32? weeks = 0;

        /// <summary>
        /// Day part of the difference between dates
        /// </summary>
        public Int32? Days
        {
            get
            {
                return days;
            }
        }
        public Int32? days = 0;

        /// <summary>
        /// Hour part of the difference between dates
        /// </summary>
        public Int32? Hours
        {
            get
            {
                return hours;
            }
        }
        public Int32? hours = 0;

        /// <summary>
        /// Minute part of the difference between dates
        /// </summary>
        public Int32? Minutes
        {
            get
            {
                return minutes;
            }
        }
        public Int32? minutes = 0;

        /// <summary>
        /// Second part of the difference between dates
        /// </summary>
        public Int32? Seconds
        {
            get
            {
                return seconds;
            }
        }
        public Int32? seconds = 0;

        /// <summary>
        /// Millisecond part of the difference between dates
        /// </summary>
        public Int32? Milliseconds
        {
            get
            {
                return milliseconds;
            }
        }
        public Int32? milliseconds = 0;

        /// <summary>
        /// Total difference between dates
        /// </summary>
        public TimeSpan Difference
        {
            get
            {
                return difference;
            }
        }
        private TimeSpan difference;

        /// <summary>
        /// Earlier of the two dates
        /// </summary>
        public DateTime EarlierDate
        {
            get
            {
                return earlierDate;
            }
        }
        private DateTime earlierDate = default(DateTime);

        /// <summary>
        /// Later of the two dates
        /// </summary>
        public DateTime LaterDate
        {
            get
            {
                return laterDate;
            }
        }
        private DateTime laterDate = default(DateTime);

        /// <summary>
        /// Time betwween a date and the current date
        /// Date is calculated against current date and time
        /// </summary>
        /// <param name="date">Date to calculate against current date</param>
        public DateDifferential(DateTime date)
            : this(date, DateTime.Now)
        {

        }

        /// <summary>
        /// Time betwween a date and the current date
        /// Date is calculated against current date and time
        /// <example>
        /// Example: Countdown to date 
        /// DateDifferential df = new DateDifferential(new DateTime(3500, 1, 1), DateDifferential.DetailType.Days);
        /// Response.Write(df.ToString()); 1 Millennium, 4 Centuries, 9 Decades, 2 months, 3 weeks, 5 days 
        /// </example>
        /// </summary>
        /// <param name="date">Date to calculate against current date</param>
        /// <param name="detail">Level of detail</param>
        public DateDifferential(DateTime date, DetailType detail)
            : this(date, DateTime.Now, detail)
        {

        }

        /// <summary>
        /// Time from one date to another
        /// </summary>
        /// <param name="firstDate">First date</param>
        /// <param name="secondDate">Secound date</param>
        public DateDifferential(DateTime firstDate, DateTime secondDate)
            : this(firstDate, secondDate, DetailType.Milliseconds)
        {

        }

        /// <summary>
        /// Time from one date to another
        /// </summary>
        /// <param name="firstDate">First date</param>
        /// <param name="secondDate">Secound date</param>
        /// <param name="detail">Level of detail</param>
        public DateDifferential(DateTime firstDate, DateTime secondDate, DetailType detail)
            : this(firstDate, secondDate, true, true, true, true, true, true, true, detail)
        {

        }

        /// <summary>
        /// Time from one date to another
        /// </summary>
        /// <example>
        /// Example: Calculate age or time since birth 
        /// DateDifferential df = new DateDifferential(new DateTime(1978, 4, 19),DateTime.Now,false,false,false,true,true,false,true, DateDifferential.DetailType.Days);
        /// Response.Write(df.ToString()); 
        /// Result "31 years, 5 months, 16 days"
        /// </example>
        /// <param name="firstDate">First date</param>
        /// <param name="secondDate">Secound date</param>
        /// <param name="CalculateMillennia">Calculate Millennia</param>
        /// <param name="CalculateCenturies">Calculate Centuries</param>
        /// <param name="CalculateDecades">Calculate Decades</param>
        /// <param name="CalculateYears">Calculate Years</param>
        /// <param name="CalculateMonths">Calculate Months</param>
        /// <param name="CalculateWeeks">Calculate Weeks</param>
        /// <param name="CalculateDays">Calculate Days</param>
        /// <param name="detail">Level of detail</param>
        public DateDifferential(DateTime firstDate, DateTime secondDate,
            Boolean CalculateMillennia,
            Boolean CalculateCenturies,
            Boolean CalculateDecades,
            Boolean CalculateYears,
            Boolean CalculateMonths,
            Boolean CalculateWeeks,
            Boolean CalculateDays,
            DetailType detail)
        {
            amountOfDetail = detail;
            if (detail.CompareTo(DetailType.Milliseconds) < 0
                && (firstDate.Millisecond > 0 || secondDate.Millisecond > 0))
            {
                firstDate.AddMilliseconds(-firstDate.Millisecond);
                secondDate.AddMilliseconds(-secondDate.Millisecond);
                firstDate.AddSeconds(1);
                secondDate.AddSeconds(1);
            }
            if (detail.CompareTo(DetailType.Seconds) < 0
                && (firstDate.Second > 0 || secondDate.Second > 0))
            {
                firstDate.AddSeconds(-firstDate.Second);
                secondDate.AddSeconds(-secondDate.Second);
                firstDate.AddMinutes(1);
                secondDate.AddMinutes(1);
            }
            if (detail.CompareTo(DetailType.Minutes) < 0
                && (firstDate.Minute > 0 || secondDate.Minute > 0))
            {
                firstDate.AddMinutes(-firstDate.Minute);
                secondDate.AddMinutes(-secondDate.Minute);
                firstDate.AddHours(1);
                secondDate.AddHours(1);
            }
            if (detail.CompareTo(DetailType.Hours) < 0
                && (firstDate.Hour > 0 || secondDate.Hour > 0))
            {
                firstDate.AddHours(-firstDate.Hour);
                secondDate.AddHours(-secondDate.Hour);
                firstDate.AddDays(1);
                secondDate.AddDays(1);
            }


            if (firstDate.Year == secondDate.Year
                 && firstDate.Month == secondDate.Month
                 && firstDate.Day == secondDate.Day
                 && firstDate.Hour == secondDate.Hour
                 && firstDate.Minute == secondDate.Minute
                 && firstDate.Second == secondDate.Second
                 && firstDate.Millisecond == secondDate.Millisecond)
            {
                type = DateDifferentialType.Equal;
            }
            else if (firstDate > secondDate)
            {
                type = DateDifferentialType.Descending;
            }
            else
            {
                type = DateDifferentialType.Ascending;
            }

            earlierDate = (firstDate > secondDate) ? secondDate : firstDate;
            laterDate = (firstDate > secondDate) ? firstDate : secondDate;

            if (type == DateDifferentialType.Equal)
                return;

            difference = laterDate.Subtract(earlierDate);

            DateTime tempLaterDate = laterDate;

            if (Difference.TotalDays >= 365249 && CalculateMillennia)
            {
                millennia = 0;
                // getting number of millennium
                while (tempLaterDate.CompareTo(earlierDate) >= 0)
                {
                    millennia++;
                    tempLaterDate = tempLaterDate.AddYears(-1000);
                }
                tempLaterDate = tempLaterDate.AddYears(1000);
                millennia--;
            }

            if (Difference.TotalDays >= 36524 && CalculateCenturies)
            {
                centuries = 0;
                // getting number of centuries
                while (tempLaterDate.CompareTo(earlierDate) >= 0)
                {
                    centuries++;
                    tempLaterDate = tempLaterDate.AddYears(-100);
                }
                tempLaterDate = tempLaterDate.AddYears(100);
                centuries--;
            }

            if (Difference.TotalDays >= 3653 && CalculateDecades)
            {
                decades = 0;
                // getting number of years
                while (tempLaterDate.CompareTo(earlierDate) >= 0)
                {
                    decades++;
                    tempLaterDate = tempLaterDate.AddYears(-10);
                }
                tempLaterDate = tempLaterDate.AddYears(10);
                decades--;
            }

            if (Difference.TotalDays >= 365 && CalculateYears)
            {
                years = 0;
                // getting number of years
                while (tempLaterDate.CompareTo(earlierDate) >= 0)
                {
                    years++;
                    tempLaterDate = tempLaterDate.AddYears(-1);
                }
                tempLaterDate = tempLaterDate.AddYears(1);
                years--;
            }

            if (CalculateMonths)
            {
                months = 0;
                // getting number of months
                while (tempLaterDate.CompareTo(earlierDate) >= 0)
                {
                    months++;
                    tempLaterDate = tempLaterDate.AddMonths(-1);
                }
                tempLaterDate = tempLaterDate.AddMonths(1);
                months--;
            }

            if (CalculateWeeks)
            {
                weeks = 0;
                // getting number of weeks
                while (tempLaterDate.CompareTo(earlierDate) >= 0)
                {
                    weeks++;
                    tempLaterDate = tempLaterDate.AddDays(-7);
                }
                tempLaterDate = tempLaterDate.AddDays(7);
                weeks--;
            }

            if (CalculateDays)
            {
                days = 0;
                // getting number of days
                while (tempLaterDate.CompareTo(earlierDate) >= 0)
                {
                    days++;
                    tempLaterDate = tempLaterDate.AddDays(-1);
                }
                tempLaterDate = tempLaterDate.AddDays(1);
                days--;
            }

            if (detail.CompareTo(DetailType.Hours) >= 0)
            {
                hours = 0;
                // getting number of hours
                while (tempLaterDate.CompareTo(earlierDate) >= 0)
                {
                    hours++;
                    tempLaterDate = tempLaterDate.AddHours(-1);
                }
                tempLaterDate = tempLaterDate.AddHours(1);
                hours--;
            }

            if (detail.CompareTo(DetailType.Minutes) >= 0)
            {
                minutes = 0;
                // getting number of minutes
                while (tempLaterDate.CompareTo(earlierDate) >= 0)
                {
                    minutes++;
                    tempLaterDate = tempLaterDate.AddMinutes(-1);
                }
                tempLaterDate = tempLaterDate.AddMinutes(1);
                minutes--;
            }

            if (detail.CompareTo(DetailType.Seconds) >= 0)
            {
                seconds = 0;
                // getting number of seconds
                while (tempLaterDate.CompareTo(earlierDate) >= 0)
                {
                    seconds++;
                    tempLaterDate = tempLaterDate.AddSeconds(-1);
                }
                tempLaterDate = tempLaterDate.AddSeconds(1);
                seconds--;
            }

            if (detail.CompareTo(DetailType.Milliseconds) >= 0)
            {
                milliseconds = 0;
                // getting number of milliseconds
                while (tempLaterDate.CompareTo(earlierDate) >= 0)
                {
                    milliseconds++;
                    tempLaterDate = tempLaterDate.AddMilliseconds(-1);
                }
                tempLaterDate = tempLaterDate.AddMilliseconds(1);
                milliseconds--;
            }

        }

        /// <summary>
        /// Create Differential based on the addtion or removal of time 
        /// </summary>
        /// <param name="MinDateDiff">Date Diffrence based on DateTime.MinValue</param>
        /// <param name="differentialType">Ascending (add to date) or Descending (subtract to date)</param>
        /// <returns>Date Differential that represents the difference in time</returns>
        public static DateDifferential CreateDifferential(DateTime minDateDiff, DateDifferentialType differentialType)
        {
            return CreateDifferential(minDateDiff, DateTime.Now, differentialType);
        }

        /// <summary>
        /// Create Differential based on the addtion or removal of time 
        /// </summary>
        /// <param name="MinDateDiff">Date Diffrence based on DateTime.MinValue</param>
        /// <param name="startingDate">Date to base generated date on</param>
        /// <param name="differentialType">Ascending (add to date) or Descending (subtract to date)</param>
        /// <returns>Date Differential that represents the difference in time</returns>
        public static DateDifferential CreateDifferential(DateTime minDateDiff, DateTime  startingDate, DateDifferentialType differentialType)
        {
            return CreateDifferential(0, 0, 0, minDateDiff.Year - DateTime.MinValue.Year, minDateDiff.Month - DateTime.MinValue.Month, 0, minDateDiff.Day - DateTime.MinValue.Day, minDateDiff.Hour - DateTime.MinValue.Hour, minDateDiff.Minute - DateTime.MinValue.Minute, minDateDiff.Second - DateTime.MinValue.Second, minDateDiff.Millisecond - DateTime.MinValue.Millisecond, differentialType, DetailType.Milliseconds, startingDate);
        }

        /// <summary>
        /// Create Differential based on the addtion or removal of time 
        /// </summary>
        /// <param name="millennia">Millennium Offset</param>
        /// <param name="centuries">Century Offset</param>
        /// <param name="decades">Decade Offset</param>
        /// <param name="years">Year Offset</param>
        /// <param name="months">Month Offset</param>
        /// <param name="weeks">Week Offset</param>
        /// <param name="days">Day Offset</param>
        /// <param name="hours">Hour Offset</param>
        /// <param name="minutes">Minute Offset</param>
        /// <param name="seconds">Second Offset</param>
        /// <param name="milliseconds">Millisecond Offset</param>
        /// <param name="differentialType">Ascending (add to date) or Descending (subtract to date)</param>
        /// <returns>Date Differential that represents the difference in time</returns>
        public static DateDifferential CreateDifferential(Int32 millennia, Int32 centuries, Int32 decades, Int32 years, Int32 months, Int32 weeks, Int32 days, Int32 hours, Int32 minutes, Int32 seconds, Int32 milliseconds, DateDifferentialType differentialType)
        {
            return CreateDifferential(millennia, centuries, decades, years, months, weeks, days, hours, minutes, seconds, milliseconds, differentialType, DetailType.Milliseconds , DateTime.Now);
        }

        /// <summary>
        /// Create Differential based on the addtion or removal of time 
        /// </summary>
        /// <param name="millennia">Millennium Offset</param>
        /// <param name="centuries">Century Offset</param>
        /// <param name="decades">Decade Offset</param>
        /// <param name="years">Year Offset</param>
        /// <param name="months">Month Offset</param>
        /// <param name="weeks">Week Offset</param>
        /// <param name="days">Day Offset</param>
        /// <param name="hours">Hour Offset</param>
        /// <param name="minutes">Minute Offset</param>
        /// <param name="seconds">Second Offset</param>
        /// <param name="milliseconds">Millisecond Offset</param>
        /// <param name="differentialType">Ascending (add to date) or Descending (subtract to date)</param>
        /// <param name="detail">Level of detail</param>
        /// <returns>Date Differential that represents the difference in time</returns>
        public static DateDifferential CreateDifferential(Int32 millennia, Int32 centuries, Int32 decades, Int32 years, Int32 months, Int32 weeks, Int32 days, Int32 hours, Int32 minutes, Int32 seconds, Int32 milliseconds, DateDifferentialType differentialType, DetailType detail)
        {
            return CreateDifferential(millennia, centuries, decades, years, months, weeks, days, hours, minutes, seconds, milliseconds, differentialType, detail, DateTime.Now);
        }
        
        /// <summary>
        /// Create Differential based on the addtion or removal of time 
        /// </summary>
        /// <param name="millennia">Millennium Offset</param>
        /// <param name="centuries">Century Offset</param>
        /// <param name="decades">Decade Offset</param>
        /// <param name="years">Year Offset</param>
        /// <param name="months">Month Offset</param>
        /// <param name="weeks">Week Offset</param>
        /// <param name="days">Day Offset</param>
        /// <param name="hours">Hour Offset</param>
        /// <param name="minutes">Minute Offset</param>
        /// <param name="seconds">Second Offset</param>
        /// <param name="milliseconds">Millisecond Offset</param>
        /// <param name="differentialType">Ascending (add to date) or Descending (subtract to date)</param>
        /// <param name="detail">Level of detail</param>
        /// <returns>Date Differential that represents the difference in time</returns>
        public static DateDifferential CreateDifferential(Int32 millennia, Int32 centuries, Int32 decades, Int32 years, Int32 months, Int32 weeks, Int32 days, Int32 hours, Int32 minutes, Int32 seconds, Int32 milliseconds, DateDifferentialType differentialType, DetailType detail, DateTime startingDate)
        {
            return CreateDifferential(millennia, centuries, decades, years, months, weeks, days, hours, minutes, seconds, milliseconds, differentialType, detail, DateTime.Now, true, true, true, true, true, true, true);
        }

        /// <summary>
        /// Create Differential based on the addtion or removal of time 
        /// </summary>
        /// <param name="millennia">Millennium Offset</param>
        /// <param name="centuries">Century Offset</param>
        /// <param name="decades">Decade Offset</param>
        /// <param name="years">Year Offset</param>
        /// <param name="months">Month Offset</param>
        /// <param name="weeks">Week Offset</param>
        /// <param name="days">Day Offset</param>
        /// <param name="hours">Hour Offset</param>
        /// <param name="minutes">Minute Offset</param>
        /// <param name="seconds">Second Offset</param>
        /// <param name="milliseconds">Millisecond Offset</param>
        /// <param name="differentialType">Ascending (add to date) or Descending (subtract to date)</param>
        /// <param name="detail">Level of detail</param>
        /// <param name="startingDate">Date to base generated date on</param>
        /// <param name="CalculateMillennia">Calculate Millennia</param>
        /// <param name="CalculateCenturies">Calculate Centuries</param>
        /// <param name="CalculateDecades">Calculate Decades</param>
        /// <param name="CalculateYears">Calculate Years</param>
        /// <param name="CalculateMonths">Calculate Months</param>
        /// <param name="CalculateWeeks">Calculate Weeks</param>
        /// <param name="CalculateDays">Calculate Days</param>
        /// <returns>Date Differential that represents the difference in time</returns>
        public static DateDifferential CreateDifferential(Int32 millennia, Int32 centuries, Int32 decades, Int32 years, Int32 months, Int32 weeks, Int32 days, Int32 hours, Int32 minutes, Int32 seconds, Int32 milliseconds, DateDifferentialType differentialType, DetailType detail, DateTime startingDate,
                        Boolean calculateMillennia,Boolean calculateCenturies,Boolean calculateDecades,Boolean calculateYears,Boolean calculateMonths,Boolean calculateWeeks,Boolean calculateDays)
        {
            DateTime tempLaterDate = startingDate;
            DateTime tempEarlierDate = startingDate;
            if (differentialType == DateDifferentialType.Ascending)
            {

                tempLaterDate = tempLaterDate.AddYears(millennia * 1000);
                tempLaterDate = tempLaterDate.AddYears(centuries * 100);
                tempLaterDate = tempLaterDate.AddYears(decades * 10);
                tempLaterDate = tempLaterDate.AddYears(years);
                tempLaterDate = tempLaterDate.AddMonths(months);
                tempLaterDate = tempLaterDate.AddDays(weeks * 7);
                tempLaterDate = tempLaterDate.AddHours(hours);
                tempLaterDate = tempLaterDate.AddMinutes(minutes);
                tempLaterDate = tempLaterDate.AddSeconds(seconds);
                tempLaterDate = tempLaterDate.AddMilliseconds(milliseconds);
                return new DateDifferential(tempLaterDate, tempEarlierDate, calculateMillennia, calculateCenturies, calculateDecades, calculateYears, calculateMonths, calculateWeeks,calculateDays, detail);
            }
            if (differentialType == DateDifferentialType.Descending)
            {
                tempEarlierDate = tempEarlierDate.AddYears(-millennia * 1000);
                tempEarlierDate = tempEarlierDate.AddYears(-centuries * 100);
                tempEarlierDate = tempEarlierDate.AddYears(-decades * 10);
                tempEarlierDate = tempEarlierDate.AddYears(-years);
                tempEarlierDate = tempEarlierDate.AddMonths(-months);
                tempEarlierDate = tempEarlierDate.AddDays(-weeks * 7);
                tempEarlierDate = tempEarlierDate.AddHours(-hours);
                tempEarlierDate = tempEarlierDate.AddMinutes(-minutes);
                tempEarlierDate = tempEarlierDate.AddSeconds(-seconds);
                tempEarlierDate = tempEarlierDate.AddMilliseconds(-milliseconds);
                return new DateDifferential(tempEarlierDate, tempLaterDate, calculateMillennia, calculateCenturies, calculateDecades, calculateYears, calculateMonths, calculateWeeks, calculateDays, detail);
            }
            else
            {
                return new DateDifferential(tempEarlierDate, tempLaterDate, calculateMillennia, calculateCenturies, calculateDecades, calculateYears, calculateMonths, calculateWeeks, calculateDays, detail);
            }
        }

        /// <summary>
        /// Description of the difference in dates in detail
        /// </summary>
        /// <returns></returns>
        public override String ToString()
        {
            String textResult = "";
            if (Millennia.HasValue && Millennia > 0)
                textResult += Millennia.ToString() + " Millenni" + ((Millennia > 1) ? "a" : "um");

            if (Centuries.HasValue && Centuries > 0)
                textResult += (textResult != "" ? ", " : "") + Centuries.ToString() + " Centur" + ((Centuries > 1) ? "ies" : "y");

            if (Decades.HasValue && Decades > 0)
                textResult += (textResult != "" ? ", " : "") + Decades.ToString() + " Decade" + ((Decades > 1) ? "s" : "");

            if (Years.HasValue && Years > 0)
                textResult += (textResult != "" ? ", " : "") + Years.ToString() + " year" + ((Years > 1) ? "s" : "");

            if (Months.HasValue && Months > 0)
                textResult += (textResult != "" ? ", " : "") + Months.ToString() + " month" + ((Months > 1) ? "s" : "");

            if (Weeks.HasValue && Weeks > 0)
                textResult += (textResult != "" ? ", " : "") + Weeks.ToString() + " week" + ((Weeks > 1) ? "s" : "");

            if (Days.HasValue && Days > 0)
                textResult += (textResult != "" ? ", " : "") + Days.ToString() + " day" + ((Days > 1) ? "s" : "");

            if (Hours.HasValue && Hours > 0)
                textResult += (textResult != "" ? ", " : "") + Hours.ToString() + " Hour" + ((Hours > 1) ? "s" : "");

            if (Minutes.HasValue && Minutes > 0)
                textResult += (textResult != "" ? ", " : "") + Minutes.ToString() + " Minute" + ((Minutes > 1) ? "s" : "");

            if (Seconds.HasValue && Seconds > 0)
                textResult += (textResult != "" ? ", " : "") + Seconds.ToString() + " Second" + ((Seconds > 1) ? "s" : "");

            if (Milliseconds.HasValue && Milliseconds > 0)
                textResult += (textResult != "" ? ", " : "") + Milliseconds.ToString() + " Millisecond" + ((Milliseconds > 1) ? "s" : "");

            String[] textResultSplit = textResult.Split(',');
            if (textResultSplit.Length > 1)
                textResult = textResult.Replace(((textResultSplit.Length == 2) ? "," : "") + textResultSplit[textResultSplit.Length - 1], " and " + textResultSplit[textResultSplit.Length - 1]);

            return textResult;
        }
    }
}